package rpc.core.plugin.impl.proxy;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import rpc.bootstrap.springboot.Bootstrap;
import rpc.core.BaseAsyncFlow;
import rpc.core.FlowReq;
import rpc.core.FlowRes;
import rpc.utils.ReflectionUtils;

public class FlowServiceProxy implements ServiceProxy {

  private static final Logger logger = LoggerFactory.getLogger(FlowServiceProxy.class);
  private String flowName;
  private ExecutorService executorService;
  private Class<?> flowClazz;
  private ApplicationContext context;
  private Environment environment;

  private AsyncFlowService asyncFlowService;
  private Bootstrap bootstrap;

  public FlowServiceProxy setAsyncFlowService(AsyncFlowService asyncFlowService) {
    this.asyncFlowService = asyncFlowService;
    return this;
  }

  public FlowServiceProxy setBootstrap(Bootstrap bootstrap) {
    this.bootstrap = bootstrap;
    return this;
  }

  public FlowServiceProxy setExecutorService(ExecutorService executorService) {
    this.executorService = executorService;
    return this;
  }

  @Override
  public ServiceProxy init() {

    return this;
  }

  @Override
  public CompletableFuture<FlowRes> invoke(FlowReq req) {
    try {

      BaseAsyncFlow flow = (BaseAsyncFlow) ReflectionUtils.newObject(flowClazz);
      flow.setContext(getContext()).setEnvironment(getEnvironment()).setExecutorService(executorService).setReq(req)
          .setBootstrap(bootstrap).setAsyncFlowService(asyncFlowService).init();
      return flow.handle(req);
    } catch (Exception e) {
      logger.error("exception:{} stackTrace:{}", e.getMessage());
      return CompletableFuture.completedFuture(new FlowRes().fail(-817).msg(e));
    }
  }

  public ApplicationContext getContext() {
    return context;
  }

  public FlowServiceProxy setContext(ApplicationContext context) {
    this.context = context;
    return this;
  }

  public Environment getEnvironment() {
    return environment;
  }

  public FlowServiceProxy setEnvironment(Environment environment) {
    this.environment = environment;
    return this;
  }

  public FlowServiceProxy setFlowName(String flowName) {
    this.flowName = flowName;
    return this;
  }

  public FlowServiceProxy setFlowClass(Class<?> flowClazz) {
    this.flowClazz = flowClazz;
    return this;
  }
}
